package com.zzw.service.Impl;

import com.zzw.bean.Product;
import com.zzw.bean.ProductES;
import com.zzw.dao.ProductMapper;
import com.zzw.service.ProductESService;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

@Service
public class ProductESServiceImpl implements ProductESService {

    private static final String PRODUCT_INDEX = "product";

    @Autowired
    private RestHighLevelClient elasticsearchClient;

    @Autowired
    private ProductMapper productMapper;

    @Override
    public boolean createProductIndex() throws IOException {
        // 判断索引是否已存在
        GetIndexRequest getRequest = new GetIndexRequest(PRODUCT_INDEX);
        boolean exists = elasticsearchClient.indices().exists(getRequest, RequestOptions.DEFAULT);
        if (exists) {
            return true;
        }

        // 创建索引请求
        CreateIndexRequest request = new CreateIndexRequest(PRODUCT_INDEX);

        // 索引设置
        request.settings(Settings.builder()
                .put("index.number_of_shards", 3)
                .put("index.number_of_replicas", 1)
        );

        // 创建索引映射
        XContentBuilder builder = XContentFactory.jsonBuilder();
        builder.startObject();
        {
            builder.startObject("properties");
            {
                builder.startObject("id");
                {
                    builder.field("type", "integer");
                }
                builder.endObject();

                builder.startObject("productCode");
                {
                    builder.field("type", "keyword");
                }
                builder.endObject();

                builder.startObject("productName");
                {
                    builder.field("type", "text");
                    builder.field("analyzer", "ik_max_word");
                    builder.field("search_analyzer", "ik_smart");
                    builder.startObject("fields");
                    {
                        builder.startObject("keyword");
                        {
                            builder.field("type", "keyword");
                        }
                        builder.endObject();
                    }
                    builder.endObject();
                }
                builder.endObject();

                builder.startObject("categoryId");
                {
                    builder.field("type", "integer");
                }
                builder.endObject();

                builder.startObject("categoryName");
                {
                    builder.field("type", "keyword");
                }
                builder.endObject();

                builder.startObject("price");
                {
                    builder.field("type", "scaled_float");
                    builder.field("scaling_factor", 100);
                }
                builder.endObject();

                builder.startObject("unit");
                {
                    builder.field("type", "keyword");
                }
                builder.endObject();

                builder.startObject("specification");
                {
                    builder.field("type", "text");
                    builder.field("analyzer", "ik_max_word");
                    builder.field("search_analyzer", "ik_smart");
                }
                builder.endObject();

                builder.startObject("description");
                {
                    builder.field("type", "text");
                    builder.field("analyzer", "ik_max_word");
                    builder.field("search_analyzer", "ik_smart");
                }
                builder.endObject();

                builder.startObject("imageUrl");
                {
                    builder.field("type", "keyword");
                    builder.field("index", false);
                }
                builder.endObject();

                builder.startObject("status");
                {
                    builder.field("type", "integer");
                }
                builder.endObject();

                builder.startObject("createTime");
                {
                    builder.field("type", "date");
                    builder.field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis");
                }
                builder.endObject();

                builder.startObject("updateTime");
                {
                    builder.field("type", "date");
                    builder.field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis");
                }
                builder.endObject();

                builder.startObject("salesCount");
                {
                    builder.field("type", "integer");
                }
                builder.endObject();

                builder.startObject("score");
                {
                    builder.field("type", "float");
                }
                builder.endObject();
            }
            builder.endObject();
        }
        builder.endObject();

        request.mapping(builder);

        // 发送请求
        CreateIndexResponse createIndexResponse = elasticsearchClient.indices().create(request, RequestOptions.DEFAULT);

        // 处理响应
        return createIndexResponse.isAcknowledged();
    }

    @Override
    public boolean deleteProductIndex() throws IOException {
        // 判断索引是否已存在
        GetIndexRequest getRequest = new GetIndexRequest(PRODUCT_INDEX);
        boolean exists = elasticsearchClient.indices().exists(getRequest, RequestOptions.DEFAULT);
        if (!exists) {
            return true;
        }

        // 删除索引请求
        DeleteIndexRequest request = new DeleteIndexRequest(PRODUCT_INDEX);

        // 发送请求
        return elasticsearchClient.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged();
    }

    @Override
    public boolean isExists(Integer id) throws IOException {
        GetRequest getRequest = new GetRequest(PRODUCT_INDEX, id.toString());
        return elasticsearchClient.exists(getRequest, RequestOptions.DEFAULT);
    }

    @Override
    public boolean saveProduct(ProductES productES) throws IOException {
        // 创建请求
        IndexRequest request = new IndexRequest(PRODUCT_INDEX);
        // 设置文档id
        request.id(productES.getId().toString());

        // 将对象转换为json
        String jsonString = convertProductESToJson(productES);

        request.source(jsonString, XContentType.JSON);

        // 发送请求
        IndexResponse response = elasticsearchClient.index(request, RequestOptions.DEFAULT);

        return "CREATED".equals(response.getResult().name()) || "UPDATED".equals(response.getResult().name());
    }

    @Override
    public boolean saveProductBatch(List<ProductES> productESList) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();

        for (ProductES productES : productESList) {
            // 创建IndexRequest
            IndexRequest request = new IndexRequest(PRODUCT_INDEX);
            request.id(productES.getId().toString());

            // 将对象转换为json
            String jsonString = convertProductESToJson(productES);

            request.source(jsonString, XContentType.JSON);

            // 添加到批量请求
            bulkRequest.add(request);
        }

        // 批量提交
        BulkResponse bulkResponse = elasticsearchClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        // 检查是否有失败
        return !bulkResponse.hasFailures();
    }

    @Override
    public boolean syncProductData() throws IOException {
        // 获取所有商品
        List<Product> products = productMapper.selectAllProducts();

        List<ProductES> productESList = new ArrayList<>();
        for (Product product : products) {
            // 转换为ES文档对象
            ProductES productES = ProductES.convertFromProduct(product);
            productESList.add(productES);
        }

        // 批量保存
        return saveProductBatch(productESList);
    }

    @Override
    public boolean updateProduct(ProductES productES) throws IOException {
        // 创建更新请求
        UpdateRequest request = new UpdateRequest(PRODUCT_INDEX, productES.getId().toString());

        // 将对象转换为json
        String jsonString = convertProductESToJson(productES);

        request.doc(jsonString, XContentType.JSON);

        // 发送请求
        UpdateResponse response = elasticsearchClient.update(request, RequestOptions.DEFAULT);

        return "UPDATED".equals(response.getResult().name());
    }

    @Override
    public boolean deleteProduct(Integer id) throws IOException {
        // 创建删除请求
        DeleteRequest request = new DeleteRequest(PRODUCT_INDEX, id.toString());

        // 发送请求
        DeleteResponse response = elasticsearchClient.delete(request, RequestOptions.DEFAULT);

        return "DELETED".equals(response.getResult().name());
    }

    @Override
    public List<ProductES> searchByKeyword(String keyword, int pageNum, int pageSize) throws IOException {
        // 创建搜索请求
        SearchRequest searchRequest = new SearchRequest(PRODUCT_INDEX);

        // 构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 如果有关键词则按关键词搜索，否则获取全部
        if (keyword != null && !keyword.isEmpty()) {
            // 组合查询
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            // 商品名称搜索（加权重）
            boolQuery.should(QueryBuilders.matchQuery("productName", keyword).boost(3.0f));
            // 规格搜索
            boolQuery.should(QueryBuilders.matchQuery("specification", keyword).boost(2.0f));
            // 描述搜索
            boolQuery.should(QueryBuilders.matchQuery("description", keyword).boost(1.0f));

            sourceBuilder.query(boolQuery);
        } else {
            // 查询所有
            sourceBuilder.query(QueryBuilders.matchAllQuery());
        }

        // 分页
        sourceBuilder.from((pageNum - 1) * pageSize);
        sourceBuilder.size(pageSize);

        // 按相关性评分排序
        sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));

        // 设置查询条件
        searchRequest.source(sourceBuilder);

        // 执行搜索
        SearchResponse searchResponse = elasticsearchClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析结果
        return parseSearchResult(searchResponse);
    }

    @Override
    public Map<String, Object> searchProduct(String keyword, Integer categoryId, BigDecimal minPrice, BigDecimal maxPrice, String sort, int pageNum, int pageSize) throws IOException {
        // 创建搜索请求
        SearchRequest searchRequest = new SearchRequest(PRODUCT_INDEX);

        // 构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 构建布尔查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 只查询启用状态的商品
        boolQuery.must(QueryBuilders.termQuery("status", 1));

        // 关键词搜索
        if (keyword != null && !keyword.isEmpty()) {
            DisMaxQueryBuilder disMaxQueryBuilder = QueryBuilders.disMaxQuery();
            disMaxQueryBuilder.add(QueryBuilders.matchQuery("productName", keyword).boost(3.0f));
            disMaxQueryBuilder.add(QueryBuilders.matchQuery("specification", keyword).boost(2.0f));
            disMaxQueryBuilder.add(QueryBuilders.matchQuery("description", keyword).boost(1.0f));

            boolQuery.must(disMaxQueryBuilder);
        }

        // 分类过滤
        if (categoryId != null) {
            boolQuery.filter(QueryBuilders.termQuery("categoryId", categoryId));
        }

        // 价格区间过滤
        if (minPrice != null || maxPrice != null) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
            if (minPrice != null) {
                rangeQuery.gte(minPrice.doubleValue());
            }
            if (maxPrice != null) {
                rangeQuery.lte(maxPrice.doubleValue());
            }
            boolQuery.filter(rangeQuery);
        }

        sourceBuilder.query(boolQuery);

        // 排序
        if (sort != null && !sort.isEmpty()) {
            switch (sort) {
                case "price_asc":
                    sourceBuilder.sort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
                    break;
                case "price_desc":
                    sourceBuilder.sort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
                    break;
                case "sales_desc":
                    sourceBuilder.sort(SortBuilders.fieldSort("salesCount").order(SortOrder.DESC));
                    break;
                case "date_desc":
                    sourceBuilder.sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
                    break;
                default:
                    sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
                    break;
            }
        } else {
            // 默认按评分排序
            sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
        }

        // 分页
        sourceBuilder.from((pageNum - 1) * pageSize);
        sourceBuilder.size(pageSize);

        // 设置查询条件
        searchRequest.source(sourceBuilder);

        // 执行搜索
        SearchResponse searchResponse = elasticsearchClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析搜索结果
        List<ProductES> productList = parseSearchResult(searchResponse);

        // 返回结果
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("list", productList);
        resultMap.put("total", searchResponse.getHits().getTotalHits().value);

        return resultMap;
    }

    @Override
    public List<ProductES> getRelatedProducts(Integer productId, int size) throws IOException {
        // 先获取当前商品信息
        GetRequest getRequest = new GetRequest(PRODUCT_INDEX, productId.toString());
        if (!elasticsearchClient.exists(getRequest, RequestOptions.DEFAULT)) {
            return new ArrayList<>();
        }

        // 创建搜索请求
        SearchRequest searchRequest = new SearchRequest(PRODUCT_INDEX);

        // 构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 根据商品ID获取商品的分类ID
        Product product = productMapper.selectProductById(productId);
        if (product == null) {
            return new ArrayList<>();
        }

        // 查询同分类的其他商品
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("status", 1)); // 只查询启用状态的商品
        boolQuery.must(QueryBuilders.termQuery("categoryId", product.getCategoryId())); // 同分类
        boolQuery.mustNot(QueryBuilders.termQuery("id", productId)); // 排除当前商品

        sourceBuilder.query(boolQuery);

        // 按销量和评分排序
        sourceBuilder.sort(SortBuilders.fieldSort("salesCount").order(SortOrder.DESC));
        sourceBuilder.sort(SortBuilders.fieldSort("score").order(SortOrder.DESC));

        // 限制返回数量
        sourceBuilder.size(size);

        // 设置查询条件
        searchRequest.source(sourceBuilder);

        // 执行搜索
        SearchResponse searchResponse = elasticsearchClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析结果
        return parseSearchResult(searchResponse);
    }

    @Override
    public List<ProductES> getHotProducts(int size) throws IOException {
        // 创建搜索请求
        SearchRequest searchRequest = new SearchRequest(PRODUCT_INDEX);

        // 构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 只查询启用状态的商品
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("status", 1));

        sourceBuilder.query(boolQuery);

        // 按销量排序
        sourceBuilder.sort(SortBuilders.fieldSort("salesCount").order(SortOrder.DESC));

        // 限制返回数量
        sourceBuilder.size(size);

        // 设置查询条件
        searchRequest.source(sourceBuilder);

        // 执行搜索
        SearchResponse searchResponse = elasticsearchClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析结果
        return parseSearchResult(searchResponse);
    }

    /**
     * 解析搜索结果
     */
    private List<ProductES> parseSearchResult(SearchResponse searchResponse) {
        List<ProductES> productList = new ArrayList<>();

        // 遍历搜索结果
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();

            ProductES productES = new ProductES();
            productES.setId((Integer) sourceAsMap.get("id"));
            productES.setProductCode((String) sourceAsMap.get("productCode"));
            productES.setProductName((String) sourceAsMap.get("productName"));
            productES.setCategoryId((Integer) sourceAsMap.get("categoryId"));
            productES.setCategoryName((String) sourceAsMap.get("categoryName"));

            // ES可能会将数值类型的数据还原时变成不同类型
            Object priceObj = sourceAsMap.get("price");
            if (priceObj instanceof Double) {
                productES.setPrice(BigDecimal.valueOf((Double) priceObj));
            } else if (priceObj instanceof Integer) {
                productES.setPrice(BigDecimal.valueOf((Integer) priceObj));
            }

            productES.setUnit((String) sourceAsMap.get("unit"));
            productES.setSpecification((String) sourceAsMap.get("specification"));
            productES.setDescription((String) sourceAsMap.get("description"));
            productES.setImageUrl((String) sourceAsMap.get("imageUrl"));

            // 状态可能是Integer或Long类型
            Object statusObj = sourceAsMap.get("status");
            if (statusObj instanceof Integer) {
                productES.setStatus((Integer) statusObj);
            } else if (statusObj instanceof Long) {
                productES.setStatus(((Long) statusObj).intValue());
            }

            // 销量
            Object salesCountObj = sourceAsMap.get("salesCount");
            if (salesCountObj instanceof Integer) {
                productES.setSalesCount((Integer) salesCountObj);
            } else if (salesCountObj instanceof Long) {
                productES.setSalesCount(((Long) salesCountObj).intValue());
            }

            // 评分
            Object scoreObj = sourceAsMap.get("score");
            if (scoreObj instanceof Double) {
                productES.setScore(((Double) scoreObj).floatValue());
            } else if (scoreObj instanceof Float) {
                productES.setScore((Float) scoreObj);
            }

            productList.add(productES);
        }

        return productList;
    }

    /**
     * 将ProductES对象转换为JSON字符串
     */
    private String convertProductESToJson(ProductES productES) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", productES.getId());
        map.put("productCode", productES.getProductCode());
        map.put("productName", productES.getProductName());
        map.put("categoryId", productES.getCategoryId());
        map.put("categoryName", productES.getCategoryName());
        map.put("price", productES.getPrice());
        map.put("unit", productES.getUnit());
        map.put("specification", productES.getSpecification());
        map.put("description", productES.getDescription());
        map.put("imageUrl", productES.getImageUrl());
        map.put("status", productES.getStatus());
        map.put("createTime", productES.getCreateTime());
        map.put("updateTime", productES.getUpdateTime());
        map.put("salesCount", productES.getSalesCount());
        map.put("score", productES.getScore());

        // 使用Jackson或Gson转换为JSON
        return new com.google.gson.Gson().toJson(map);
    }
}
